#include "CHIP_ADC_module/CHIP_ADC.hpp"

#ifdef DBG_TAG
#undef DBG_TAG
#endif
#ifdef DBG_LVL
#undef DBG_LVL
#endif

#define DBG_TAG     "CHIP_ADC"
#define DBG_LVL     DBG_LOG

extern "C"
{
#include <rtdbg.h>
}

using namespace std;

CHIP_ADC::~CHIP_ADC()
{
    if(latest_value_lock)
        rt_mutex_delete(latest_value_lock);
}

CHIP_ADC::CHIP_ADC(std::string adc_dev_name,
                   uint32_t adc_channel,
                   int sample_num_per_mesure,
                   FA_Filter_Type filter_type,
                   double (*transfer_adc_value_to_need)(uint32_t adc_value))
{
    this->adc_dev_name = adc_dev_name;
    this->latest_value = 0;
    if (sample_num_per_mesure <= 0)
    {
        LOG_E("error: adc dev <%s> not allow sample num < 0", adc_dev_name.c_str());
        goto end;
    }
    this->sample_num_per_mesure = sample_num_per_mesure;

    switch (filter_type)
    {
    case FA_Filter_Type_MV: //中位值滤波算法
        this->_filter = FA_Median_Value_Filtering_Algorithm;
        break;
    case FA_Filter_Type_AA: //算术平均滤波算法
        this->_filter = FA_Arithmetic_Average_Filtering_Algorithm;
        break;
    default:
        LOG_E("error: adc dev <%s> not allow filter algorithm <%d>", adc_dev_name.c_str(), filter_type);
        goto end;
    }
    this->filter_type = filter_type;

    if (!transfer_adc_value_to_need)
    {
        LOG_E("error: transfer function is NULL ,adc dev <%s> must have a transfer function",
              adc_dev_name.c_str());
        goto end;
    }
    this->_transfer_adc_value_to_need = transfer_adc_value_to_need;

    this->adc_dev = (rt_adc_device_t) rt_device_find(adc_dev_name.c_str());
    if (!this->adc_dev)
    {
        LOG_E("error: adc dev <%s> not found", adc_dev_name.c_str());
        goto end;
    }

    if (rt_adc_enable(this->adc_dev, adc_channel) != RT_EOK)
    {
        LOG_E("error: adc dev <%s> enable channel <%d> fail", adc_dev_name.c_str(), adc_channel);
        goto end;
    }
    this->adc_channel = adc_channel;

    latest_value_lock = rt_mutex_create((adc_dev_name+"_"+to_string(adc_channel)+"_lock").c_str(), RT_IPC_FLAG_PRIO);
    if(!latest_value_lock)
    {
        LOG_E("error: adc dev <%s> channel <%d> create data lock fail", adc_dev_name.c_str(), adc_channel);
        goto end;
    }

    LOG_I("adc dev <%s> channel <%d> create ok", adc_dev_name.c_str(),adc_channel);
    this->init_flag = chip_adc_status_ok;
    this->debug_flag = 0;
    return;
    end:
    LOG_E("error: adc dev <%s> channel <%d> create fail", adc_dev_name.c_str(),adc_channel);
    this->debug_flag = 0;
    this->init_flag = chip_adc_status_fail;
    return;
}

void CHIP_ADC::CHIP_ADC_open_debug()
{
    debug_flag = 1;
}

void CHIP_ADC::CHIP_ADC_close_debug()
{
    debug_flag = 0;
}

chip_adc_status CHIP_ADC::CHIP_ADC_change_channel(uint32_t new_channel)
{
    if (init_flag != chip_adc_status_ok)
    {
        LOG_E("adc dev <%s> cant change channel,pls check init", adc_dev_name.c_str());
        return chip_adc_status_fail;
    }
    rt_adc_disable(this->adc_dev, adc_channel);
    if (rt_adc_enable(this->adc_dev, new_channel) != RT_EOK)
    {
        LOG_E("error: adc dev <%s> change channel from <%d> to <%d> fail",
              adc_dev_name.c_str(),
              adc_channel,
              new_channel);
        rt_adc_enable(this->adc_dev, adc_channel);
        return chip_adc_status_fail;
    }
    adc_channel = new_channel;
    return chip_adc_status_ok;
}

chip_adc_status CHIP_ADC::CHIP_ADC_change_transfer_function(double (*_t_f)(uint32_t adc_value))
{
    if (init_flag != chip_adc_status_ok)
    {
        LOG_E("adc dev <%s> cant change transfer function,pls check init", adc_dev_name.c_str());
        return chip_adc_status_fail;
    }
    if (!_t_f)
    {
        LOG_E("error: adc dev <%s> change transfer function fail, input cant be NULL", adc_dev_name.c_str());
        return chip_adc_status_fail;
    }
    _transfer_adc_value_to_need = _t_f;
    return chip_adc_status_ok;
}
double CHIP_ADC::CHIP_ADC_measure()
{
    uint32_t temp;
    uint32_t value_buf[sample_num_per_mesure];
    int i ;
    double result;

    if (init_flag != chip_adc_status_ok)
    {
        LOG_E("adc dev <%s> cant measure,pls check init or channel", adc_dev_name.c_str());
        goto end;
    }

    if (debug_flag)
    LOG_D("adc dev <%s> channel <%d> sample_num_per_mesure <%d> list size <%d>", adc_dev_name.c_str(), adc_channel, sample_num_per_mesure,sizeof(value_buf)/sizeof(uint32_t));


    for (i = 0; i < sample_num_per_mesure; i++)
    {
        value_buf[i] = rt_adc_read(adc_dev, adc_channel);
        rt_thread_mdelay(1);
        if (debug_flag)
            LOG_D("adc dev <%s> channel <%d>: before filter <%d(0x%X)>",
                  adc_dev_name.c_str(),
                  adc_channel,
                  value_buf[i],
                  value_buf[i]);
    }
    temp = _filter(sample_num_per_mesure, value_buf);
    if (debug_flag)
    LOG_D("adc dev <%s> channel <%d>: after filter <%d(0x%X)>", adc_dev_name.c_str(), adc_channel, temp);

    result = _transfer_adc_value_to_need(temp);

    if (debug_flag)
    LOG_D("adc dev <%s> channel <%d>: after transfer <%.4lf>", adc_dev_name.c_str(), adc_channel, result);

    rt_mutex_take(latest_value_lock, RT_WAITING_FOREVER);
    latest_value = result;
    rt_mutex_release(latest_value_lock);

    return result;
    end: return NAN;
}

double CHIP_ADC::CHIP_ADC_read_latest_value_buff()
{
    double result;
    rt_mutex_take(latest_value_lock, RT_WAITING_FOREVER);
    result =latest_value ;
    rt_mutex_release(latest_value_lock);
    return result;
}

chip_adc_status CHIP_ADC::CHIP_ADC_read_init_status()
{
    return this->init_flag;
}

